// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.fileSystem;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;
import zombie.core.logger.ExceptionLogger;
import zombie.gameStates.GameLoadingState;

public final class FileSystemImpl extends FileSystem {
    private final ArrayList<DeviceList> m_devices = new ArrayList();
    private final ArrayList<FileSystemImpl.AsyncItem> m_in_progress = new ArrayList();
    private final ArrayList<FileSystemImpl.AsyncItem> m_pending = new ArrayList();
    private int m_last_id = 0;
    private DiskFileDevice m_disk_device;
    private MemoryFileDevice m_memory_device;
    private final HashMap<String, TexturePackDevice> m_texturepack_devices = new HashMap();
    private final HashMap<String, DeviceList> m_texturepack_devicelists = new HashMap();
    private DeviceList m_default_device;
    private final ExecutorService executor;
    private final AtomicBoolean lock = new AtomicBoolean(false);
    private final ArrayList<FileSystemImpl.AsyncItem> m_added = new ArrayList();
    public static final HashMap<String, Boolean> TexturePackCompression = new HashMap();

    public FileSystemImpl() {
        this.m_disk_device = new DiskFileDevice("disk");
        this.m_memory_device = new MemoryFileDevice();
        this.m_default_device = new DeviceList();
        this.m_default_device.add(this.m_disk_device);
        this.m_default_device.add(this.m_memory_device);
        int _int = Runtime.getRuntime().availableProcessors() <= 4 ? 2 : 4;
        this.executor = Executors.newFixedThreadPool(_int);
    }

    @Override
    public boolean mount(IFileDevice device) {
        return true;
    }

    @Override
    public boolean unMount(IFileDevice device) {
        return this.m_devices.remove(device);
    }

    @Override
    public IFile open(DeviceList deviceList, String path, int mode) {
        IFile iFile = deviceList.createFile();
        if (iFile != null) {
            if (iFile.open(path, mode)) {
                return iFile;
            } else {
                iFile.release();
                return null;
            }
        } else {
            return null;
        }
    }

    @Override
    public void close(IFile file) {
        file.close();
        file.release();
    }

    @Override
    public int openAsync(DeviceList deviceList, String path, int mode, IFileTask2Callback cb) {
        IFile iFile = deviceList.createFile();
        if (iFile != null) {
            FileSystemImpl.OpenTask openTask = new FileSystemImpl.OpenTask(this);
            openTask.m_file = iFile;
            openTask.m_path = path;
            openTask.m_mode = mode;
            openTask.m_cb = cb;
            return this.runAsync(openTask);
        } else {
            return -1;
        }
    }

    @Override
    public void closeAsync(IFile file, IFileTask2Callback cb) {
        FileSystemImpl.CloseTask closeTask = new FileSystemImpl.CloseTask(this);
        closeTask.m_file = file;
        closeTask.m_cb = cb;
        this.runAsync(closeTask);
    }

    @Override
    public void cancelAsync(int id) {
        if (id != -1) {
            for (int int0 = 0; int0 < this.m_pending.size(); int0++) {
                FileSystemImpl.AsyncItem asyncItem0 = (FileSystemImpl.AsyncItem)this.m_pending.get(int0);
                if (asyncItem0.m_id == id) {
                    asyncItem0.m_future.cancel(false);
                    return;
                }
            }

            for (int int1 = 0; int1 < this.m_in_progress.size(); int1++) {
                FileSystemImpl.AsyncItem asyncItem1 = (FileSystemImpl.AsyncItem)this.m_in_progress.get(int1);
                if (asyncItem1.m_id == id) {
                    asyncItem1.m_future.cancel(false);
                    return;
                }
            }

            while (!this.lock.compareAndSet(false, true)) {
                Thread.onSpinWait();
            }

            for (int int2 = 0; int2 < this.m_added.size(); int2++) {
                FileSystemImpl.AsyncItem asyncItem2 = (FileSystemImpl.AsyncItem)this.m_added.get(int2);
                if (asyncItem2.m_id == id) {
                    asyncItem2.m_future.cancel(false);
                    break;
                }
            }

            this.lock.set(false);
        }
    }

    @Override
    public InputStream openStream(DeviceList deviceList, String path) throws IOException {
        return deviceList.createStream(path);
    }

    @Override
    public void closeStream(InputStream stream) {
    }

    private int runAsync(FileSystemImpl.AsyncItem asyncItem) {
        Thread thread = Thread.currentThread();
        if (thread != zombie.GameWindow.GameThread && thread != GameLoadingState.loader) {
            boolean _boolean = true;
        }

        while (!this.lock.compareAndSet(false, true)) {
            Thread.onSpinWait();
        }

        asyncItem.m_id = this.m_last_id++;
        if (this.m_last_id < 0) {
            this.m_last_id = 0;
        }

        this.m_added.add(asyncItem);
        this.lock.set(false);
        return asyncItem.m_id;
    }

    @Override
    public int runAsync(FileTask fileTask) {
        FileSystemImpl.AsyncItem asyncItem = new FileSystemImpl.AsyncItem();
        asyncItem.m_task = fileTask;
        asyncItem.m_future = new FutureTask(fileTask);
        return this.runAsync(asyncItem);
    }

    @Override
    public void updateAsyncTransactions() {
        int int0 = Math.min(this.m_in_progress.size(), 16);

        for (int int1 = 0; int1 < int0; int1++) {
            FileSystemImpl.AsyncItem asyncItem0 = (FileSystemImpl.AsyncItem)this.m_in_progress.get(int1);
            if (asyncItem0.m_future.isDone()) {
                this.m_in_progress.remove(int1--);
                int0--;
                if (asyncItem0.m_future.isCancelled()) {
                    boolean _boolean = true;
                } else {
                    Object object = null;

                    try {
                        object = asyncItem0.m_future.get();
                    } catch (Throwable throwable) {
                        ExceptionLogger.logException(throwable, asyncItem0.m_task.getErrorMessage());
                    }

                    asyncItem0.m_task.handleResult(object);
                }

                asyncItem0.m_task.done();
                asyncItem0.m_task = null;
                asyncItem0.m_future = null;
            }
        }

        while (!this.lock.compareAndSet(false, true)) {
            Thread.onSpinWait();
        }

        int int2 = 1;
        if (int2) {
            for (int int3 = 0; int3 < this.m_added.size(); int3++) {
                FileSystemImpl.AsyncItem asyncItem1 = (FileSystemImpl.AsyncItem)this.m_added.get(int3);
                int int4 = this.m_pending.size();

                for (int int5 = 0; int5 < this.m_pending.size(); int5++) {
                    FileSystemImpl.AsyncItem asyncItem2 = (FileSystemImpl.AsyncItem)this.m_pending.get(int5);
                    if (asyncItem1.m_task.m_priority > asyncItem2.m_task.m_priority) {
                        int4 = int5;
                        break;
                    }
                }

                this.m_pending.add(int4, asyncItem1);
            }
        } else {
            this.m_pending.addAll(this.m_added);
        }

        this.m_added.clear();
        this.lock.set(false);
        int2 = 16 - this.m_in_progress.size();

        while (int2 > 0 && !this.m_pending.isEmpty()) {
            FileSystemImpl.AsyncItem asyncItem3 = (FileSystemImpl.AsyncItem)this.m_pending.remove(0);
            if (!asyncItem3.m_future.isCancelled()) {
                this.m_in_progress.add(asyncItem3);
                this.executor.submit(asyncItem3.m_future);
                int2--;
            }
        }
    }

    @Override
    public boolean hasWork() {
        if (this.m_pending.isEmpty() && this.m_in_progress.isEmpty()) {
            while (!this.lock.compareAndSet(false, true)) {
                Thread.onSpinWait();
            }

            boolean _boolean = !this.m_added.isEmpty();
            this.lock.set(false);
            return _boolean;
        } else {
            return true;
        }
    }

    @Override
    public DeviceList getDefaultDevice() {
        return this.m_default_device;
    }

    @Override
    public void mountTexturePack(String name, FileSystem.TexturePackTextures subTextures, int flags) {
        TexturePackDevice texturePackDevice = new TexturePackDevice(name, flags);
        if (subTextures != null) {
            try {
                texturePackDevice.getSubTextureInfo(subTextures);
            } catch (IOException iOException) {
                ExceptionLogger.logException(iOException);
            }
        }

        this.m_texturepack_devices.put(name, texturePackDevice);
        DeviceList deviceList = new DeviceList();
        deviceList.add(texturePackDevice);
        this.m_texturepack_devicelists.put(texturePackDevice.name(), deviceList);
    }

    @Override
    public DeviceList getTexturePackDevice(String name) {
        return (DeviceList)this.m_texturepack_devicelists.get(name);
    }

    @Override
    public int getTexturePackFlags(String name) {
        return ((TexturePackDevice)this.m_texturepack_devices.get(name)).getTextureFlags();
    }

    @Override
    public boolean getTexturePackAlpha(String name, String page) {
        return ((TexturePackDevice)this.m_texturepack_devices.get(name)).isAlpha(page);
    }

    private static final class AsyncItem {
        int m_id;
        FileTask m_task;
        FutureTask<Object> m_future;
    }

    private static final class CloseTask extends FileTask {
        IFile m_file;
        IFileTask2Callback m_cb;

        CloseTask(FileSystem fileSystem) {
            super(fileSystem);
        }

        public Object call() throws Exception {
            this.m_file.close();
            this.m_file.release();
            return null;
        }

        @Override
        public void handleResult(Object object) {
            if (this.m_cb != null) {
                this.m_cb.onFileTaskFinished(this.m_file, object);
            }
        }

        @Override
        public void done() {
            this.m_file = null;
            this.m_cb = null;
        }
    }

    private static final class OpenTask extends FileTask {
        IFile m_file;
        String m_path;
        int m_mode;
        IFileTask2Callback m_cb;

        OpenTask(FileSystem fileSystem) {
            super(fileSystem);
        }

        public Object call() throws Exception {
            return this.m_file.open(this.m_path, this.m_mode);
        }

        @Override
        public void handleResult(Object object) {
            if (this.m_cb != null) {
                this.m_cb.onFileTaskFinished(this.m_file, object);
            }
        }

        @Override
        public void done() {
            if ((this.m_mode & 5) == 5) {
                this.m_file_system.closeAsync(this.m_file, null);
            }

            this.m_file = null;
            this.m_path = null;
            this.m_cb = null;
        }
    }
}
